package Railroad;

import Railroad.Components.OperatorStation;
import Railroad.Components.Signal;
import Railroad.Components.Switch;
import Railroad.Components.TrackItem;
import Railroad.Components.TrackNode;
import Railroad.Components.Rail;
import Railroad.Components.SwitchStatus;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class NacitavanieZXML {
    // Načítanie súčastí trate zo XML.
    public ArrayList<TrackItem> nacitajItemy() { 
        ArrayList<TrackItem> list = new ArrayList<>(); // ArrayList na ukladanie itemov, ktoré bude vracať metóda.
        try {
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(openFile());
            doc.getDocumentElement().normalize();

            NodeList tItems = doc.getElementsByTagName("trackItems"); // Do listu načítava všetko medzi tagmi trackItems.

            for (int i = 0; i < tItems.getLength(); i++) { // Prechádzanie polí.
                Node trackItems = tItems.item(i); // Uloženie prvku poľa do uzla.
                Element trackElement = (Element) trackItems; // Pretypovanie uzla na výber ďalších tagov.
                NodeList elements = trackElement.getChildNodes();
                for (int j = 0; j < elements.getLength(); j++) {
                    Node atrib = elements.item(j);
                    if (atrib.getNodeType() == Node.ELEMENT_NODE) {
                        Element element = (Element) atrib;
                        TrackItem item = createItemFromXmlElement(element);
                        if (item != null)
                            list.add(item);
                    }
                }
            }

        }
        catch(Exception ex) {
            System.out.println("Súbor nenájdený, alebo nastala chyba pri vytváraní itemov.");
        }
        return list;
    }
    
    private InputStream openFile() {
        return Thread.currentThread().getContextClassLoader().getResourceAsStream("resources/railYard.xml");
    }
    
    // Metóda, ktorá slúži na vytváranie itemov (prvky trate).
    private TrackItem createItemFromXmlElement(Element element) { 
        try {
            switch(element.getNodeName()) { // Zistenie typu itemu cez načítanie atribútu type.         
                case "rail":
                    return new Rail(Integer.parseInt(element.getAttribute("id")), Integer.parseInt(element.getAttribute("startX")), Integer.parseInt(element.getAttribute("startY")), Integer.parseInt(element.getAttribute("endX")), Integer.parseInt(element.getAttribute("endY")), element.getAttribute("name"));//nacitanie atributov potrebnych pre vytvorenie 
                case "switch":
                    return new Switch(Integer.parseInt(element.getAttribute("id")), Integer.parseInt(element.getAttribute("startX")), Integer.parseInt(element.getAttribute("endX")), Integer.parseInt(element.getAttribute("directY")), Integer.parseInt(element.getAttribute("sideY")), Integer.parseInt(element.getAttribute("straightStart")), Integer.parseInt(element.getAttribute("straightEnd")), element.getAttribute("name"),Integer.parseInt(element.getAttribute("rychlost")));
                case "signal":
                    return new Signal(Integer.parseInt(element.getAttribute("id")), Integer.parseInt(element.getAttribute("startX")), Integer.parseInt(element.getAttribute("startY")), element.getAttribute("direction"), Integer.parseInt(element.getAttribute("main")), element.getAttribute("name"));
                case "operator":
                    final String TimeFormatString = "HH:mm";
                    final SimpleDateFormat timeFormat = new SimpleDateFormat(TimeFormatString, Locale.getDefault());
                    Date dayStart = timeFormat.parse(element.getAttribute("dayStart"));
                    Date dayEnd = timeFormat.parse(element.getAttribute("dayEnd"));
                    return new OperatorStation(Integer.parseInt(element.getAttribute("id")), Integer.parseInt(element.getAttribute("startX")), Integer.parseInt(element.getAttribute("startY")), dayStart, dayEnd, "up".equals(element.getAttribute("direction")));
                default:
                    return null;
            }
        }
        catch (Exception e) {
            return null;
        }
    }
    
    // Načítanie ciest. Parametrom sú načítané itemy, aby ich bolo možné obsadiť a pod.   
    public List<Track> nacitajCesty(Zoznam prvky) {
        List<Track> trackList = new ArrayList<>(); // Zoznam ciest.
        try {
            
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(openFile());
            doc.getDocumentElement().normalize();

            NodeList tItems = doc.getElementsByTagName("route"); // Načíta cesty.

            for(int i = 0; i < tItems.getLength(); i++) {
                Node trackItems = tItems.item(i);
                Element trackElement = (Element) trackItems; // Pretypovanie nutné na výber ďalších tagov.

                int trackId = Integer.parseInt(trackElement.getAttribute("id")); // Zistenie ID pridávanej cesty. 
                boolean frameshift = Boolean.parseBoolean(trackElement.getAttribute("frameshift")); // Načítanie atribútu, či sa jedná o posunovú(1) alebo normálnu cestu(0).
                Track trat = new Track(trackId, frameshift); // Vytvorenie novej cesty.
                NodeList itemElementu = trackElement.getElementsByTagName("item"); // Zloženie trate z výhybiek a koľají. 
                NodeList signalElemet = trackElement.getElementsByTagName("startingSignal"); // Návestidlo na ceste.
                NodeList switchElement = trackElement.getElementsByTagName("position"); // Nastavenie výhybiek.
                NodeList routeElement = trackElement.getElementsByTagName("nextRoute"); // Nastavenie nasldujucej cesty.
                NodeList postRouteElement = trackElement.getElementsByTagName("postRoute"); // Nastavenie nasldujucej cesty.
                
                for(int j = 0; j < itemElementu.getLength(); j++) { // Pridanie výhybiek a koľají do trate.
                    Node Atrib = itemElementu.item(j);
                    if(Atrib.getNodeType() == Node.ELEMENT_NODE) {
                        Element element = (Element) Atrib;
                        String elementId = element.getAttribute("id"); // Vráti ID zapísane v XML.
                        TrackItem item = prvky.vratHladany(elementId); // Vyhľadá prvok so zadaným ID.
                        if(item == null) 
                            System.out.println("Prvok s ID "+elementId+" definovaný v trati "+trackId+ " neexistuje.");
                        else if(item instanceof TrackNode) {
                            TrackNode node = (TrackNode) item;
                            trat.addItem(node); // Pridanie nájdeného itemu do trate.
                        }
                        else 
                            System.out.println("Prvok s ID "+elementId+" nie je koľaj ani výhybka.");
                    }
                }
                
                for(int j = 0; j < signalElemet.getLength(); j++) { // Pridanie návestidiel.
                    Node Atrib = signalElemet.item(j);
                    if (Atrib.getNodeType() == Node.ELEMENT_NODE) {
                        Element element = (Element) Atrib;
                        String signalId = element.getAttribute("id"); // Prečíta ID návestidla zo XML.
                        TrackItem signal = prvky.vratHladany(signalId); // Vyhľadá návestidlo podľa zadaného ID.
                        if (signal == null)
                            System.out.println("Návestidlo s ID "+signalId+" nastavené v ceste "+trackId+" neexistuje.");
                        else if (!(signal instanceof Signal))
                            System.out.println("Prvok s ID "+signalId+" nastavený v ceste "+trackId+" nie je návestidlo.");
                        else
                            trat.setStartingSignal((Signal)signal); // Pridanie návestidla do cesty.
                    }
                }
                
                for(int j = 0; j < switchElement.getLength(); j++) { // Nastavenie výhybiek na testovanie, 
                    Node Atrib = switchElement.item(j);
                    if(Atrib.getNodeType() == Node.ELEMENT_NODE) {
                        Element element = (Element) Atrib;
                        String switchId = element.getAttribute("switchId");
                        TrackItem s = prvky.vratHladany(switchId);
                        if(s == null)
                            System.out.println("Výhybka s ID " +switchId+" na ceste "+trackId+" neexituje.");
                        else if (!(s instanceof Switch))
                            System.out.println("Prvok s ID "+switchId+" nastavený v ceste "+trackId+" nie je výhybka.");
                        else{
                            Switch sw = (Switch) s;
                            if (element.getAttribute("value").compareTo("straight") == 0) 
                                trat.pridajNastavenie(sw, SwitchStatus.STRAIGHT);
                            else if(element.getAttribute("value").compareTo("side") == 0)
                                trat.pridajNastavenie(sw, SwitchStatus.SIDE);
                        }
                    }
                }
                for(int j = 0; j < routeElement.getLength(); j++) { 
                    Node Atrib = routeElement.item(j);
                    if(Atrib.getNodeType() == Node.ELEMENT_NODE) {
                        Element element = (Element) Atrib;
                        String nextRoute = element.getAttribute("id");
                        trat.setNasledujuca(Integer.parseInt(nextRoute));
                    }
                }
                for(int j = 0; j < postRouteElement.getLength(); j++) { 
                    Node Atrib = postRouteElement.item(j);
                    if(Atrib.getNodeType() == Node.ELEMENT_NODE) {
                        Element element = (Element) Atrib;
                        String postRoute = element.getAttribute("id");
                        trat.setPredchadzajuca(Integer.parseInt(postRoute));
                    }
                }
              
                trackList.add(trat);
            }
        }
        catch(NumberFormatException | ParserConfigurationException | SAXException ex) {
            System.out.println("Nastala chyba pri vytváraní trás.");
        }
        catch(IOException ex) {
            System.out.println("Chyba pri práci so súborom.");
        }
        return trackList;
    }
}